#include "curvectrl.h"
#include "dm/filter.h"



CtrlButtonGroup::CtrlButtonGroup()
{

}

CtrlButtonGroup::CtrlButtonGroup(const double &ratio, const DMVariant &dm, const QString &text)
    : selected{false}
    , text{text}
    , fg{false, true, MoveDirection::Free, QRect(0, 0, 20 * ratio, 20 * ratio)}
    , lq{false, false, MoveDirection::Horizontal, QRect(0, 0, 10 * ratio, 10 * ratio)}
    , rq{false, false, MoveDirection::Horizontal, QRect(0, 0, 10 * ratio, 10 * ratio)}
    , tbox{false, true, MoveDirection::Disabled, QRect(0, 0, 300 * ratio, 50 * ratio)}
{
    setDm(dm);
}

void CtrlButtonGroup::setDm(const DMVariant &dm)
{
    this->dm = dm;
    array = Filter::gainArray(dm);
}

void CtrlButtonGroup::draw(QPainter &painter, const QSize &size)
{
    std::visit(
        overloaded {
            [this, &painter, &size](const EQ &eq) {
                auto p = toPoint(size, eq.freq, eq.gain);
                if (eq.type == EQType::ALLPASS_90 || eq.type == EQType::ALLPASS_180) {
                    p = toPoint(size, eq.freq, EQ_GAIN_DEFAULT);
                }
                fg.rect.moveCenter(p);
                lq.rect.moveCenter(QPoint(p.x() - EQ_BW_DEFAULT - eq.bw, p.y()));
                rq.rect.moveCenter(QPoint(p.x() + EQ_BW_DEFAULT + eq.bw, p.y()));
                tbox.rect.moveCenter(p);
                if (fg.show) {
                    painter.setPen(Qt::white);  // 文本颜色
                    if (selected) {
                        int orientation = Qt::AlignHCenter;
                        if (eq.gain < EQ_GAIN_DEFAULT) {
                            orientation |= Qt::AlignBottom;
                        }
                        else {
                            orientation |= Qt::AlignTop;
                        }
                        painter.drawText(tbox.rect, orientation, QString("F: %1 %2 Q: %3 G: %4 %5").arg(eq.freq).arg(LABEL_FREQ_UNIT,
                                                                                                                     QString::number(Filter::bwToQ(eq.bw), 'f', EQ_Q_DECIMAL),
                                                                                                                     QString::number(eq.gain, 'f', EQ_GAIN_DECIMAL),
                                                                                                                     LABEL_DECIBEL_UINT));
                        painter.setBrush(Qt::white);
                        painter.drawEllipse(fg.rect);
                        painter.setPen(Qt::black);
                        painter.drawText(fg.rect, Qt::AlignCenter, text);
                    }
                    else {
                        painter.setPen(QColor(85, 87, 89));
                        painter.setBrush(QColor(85, 87, 89));
                        painter.drawEllipse(fg.rect);
                        painter.setPen(Qt::white);
                        painter.drawText(fg.rect, Qt::AlignCenter, text);
                    }
                }
                if (eq.type == EQType::PEQ) {
                    painter.setPen(QColor(85, 87, 89));
                    painter.setBrush(Qt::white);
                    if (lq.show) {
                        painter.drawEllipse(lq.rect);
                    }
                    if (rq.show) {
                        painter.drawEllipse(rq.rect);
                    }
                }

            },
            [this, &painter, &size](const Xover &xover) {
                if (fg.show) {
                    fg.rect.moveCenter(toPoint(size, xover.freq, EQ_GAIN_MAX + EQ_GAIN_MIN));
                    tbox.rect.moveCenter(fg.rect.center());
                    painter.setPen(Qt::white);
                    if (selected) {
                        if ((xover.type == XoverType::Hpf && xover.freq == EQ_FREQUENCY_MIN) ||
                            (xover.type == XoverType::Lpf && xover.freq == EQ_FREQUENCY_MAX)) {
                            // OFF
                        }
                        else {
                            painter.drawText(tbox.rect, Qt::AlignHCenter | Qt::AlignBottom, QString("F: %1 Hz").arg(xover.freq));
                        }
                        painter.setBrush(Qt::white);
                        painter.drawEllipse(fg.rect);
                        painter.setPen(Qt::black);
                        painter.drawText(fg.rect, Qt::AlignCenter, text);
                    }
                    else {
                        painter.setPen(QColor(85, 87, 89));
                        painter.setBrush(QColor(85, 87, 89));
                        painter.drawEllipse(fg.rect);
                        painter.setPen(Qt::white);
                        painter.drawText(fg.rect, Qt::AlignCenter, text);
                    }
                }
            }
        }, dm);
}

void CtrlButtonGroup::showFG(bool show)
{
    fg.show = show;
}

void CtrlButtonGroup::showLRQ(bool show)
{
    lq.show = show;
    rq.show = show;
}

void CtrlButtonGroup::setFGDirection(MoveDirection direction)
{
    fg.direction = direction;
}

void CtrlButtonGroup::setSelect(const QPoint &point)
{
    if (fg.show) {
        fg.dragging = fg.rect.contains(point);
    }
    if (lq.show) {
        lq.dragging = lq.rect.contains(point);
    }
    if (rq.show) {
        rq.dragging = rq.rect.contains(point);
    }
    selected = fg.dragging || lq.dragging || rq.dragging;
    showLRQ(selected && std::get_if<EQ>(&dm));
}

void CtrlButtonGroup::dragCancel()
{
    fg.dragging = false;
    lq.dragging = false;
    rq.dragging = false;
}

void CtrlButtonGroup::deselect()
{
    dragCancel();
    selected = false;
    showLRQ(false);
}

DMVariant CtrlButtonGroup::newDm(const QPoint &point, const QSize &size) const
{
    auto dm = this->dm;
    if (fg.dragging) {
        auto freq = Filter::widthToFreq(size.width(), point.x());
        std::visit(
            overloaded {
                [&freq, &point, &size](EQ &eq) {
                    eq.freq = freq;
                    if (eq.type == EQType::ALLPASS_90 || eq.type == EQType::ALLPASS_180) {
                        eq.gain = EQ_GAIN_DEFAULT;
                    }
                    else {
                        eq.gain = Filter::heightToGain(size.height(), point.y());
                    }
                },
                [&freq](Xover &xover) {
                    xover.freq = freq;
                }
            }, dm);
    }
    else if (lq.dragging) {
        if (const auto eq = std::get_if<EQ>(&dm)) {
            eq->bw = std::clamp(static_cast<int>(fg.rect.center().x() - EQ_BW_DEFAULT - point.x()), EQ_BW_MIN, EQ_BW_MAX);
        }
    }
    else if (rq.dragging) {
        if (const auto eq = std::get_if<EQ>(&dm)) {
            eq->bw = std::clamp(static_cast<int>(point.x() - fg.rect.center().x() - EQ_BW_DEFAULT), EQ_BW_MIN, EQ_BW_MAX);
        }
    }

    return dm;
}

bool CtrlButtonGroup::dragging() const
{
    return fg.dragging || lq.dragging || rq.dragging;
}

bool CtrlButtonGroup::contains(const QPoint &point) const
{
    if (containsFG(point) || containsLQ(point) || containsRQ(point)) {
        return true;
    }
    return false;
}

bool CtrlButtonGroup::containsFG(const QPoint &point) const
{
    return fg.show && fg.rect.contains(point);
}

bool CtrlButtonGroup::containsLQ(const QPoint &point) const
{
    return lq.show && lq.rect.contains(point);
}

bool CtrlButtonGroup::containsRQ(const QPoint &point) const
{
    return rq.show && rq.rect.contains(point);
}

QPointF CtrlButtonGroup::toPoint(const QSize &size, const double &freq, const double &gain)
{
    return QPointF(size.width() * Filter::freqToWidth(freq), size.height() * Filter::gainToHeight(gain));
}
